package com.ks.comment.dao;



import com.ks.core.util.JsonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Repository
public class RedisDao {

    @Autowired
    private StringRedisTemplate template;


    public void incr(String key, int num) {
        ValueOperations<String, String> ops = template.opsForValue();
        ops.increment(key, num);
    }

    public void setKey(String key, String value) {
        ValueOperations<String, String> ops = template.opsForValue();
        ops.set(key, value);
    }


    /**
     * 设置key
     *
     * @param key
     * @param value
     * @param time  过期时间，单位分钟
     */
    public void setKey(String key, String value, int time) {
        ValueOperations<String, String> ops = template.opsForValue();
        ops.set(key, value, time, TimeUnit.MINUTES);
    }

    /**
     * 设置key
     *
     * @param key
     * @param value
     * @param time  过期时间，单位分钟
     */
    public void setKey(String key, String value, int time, TimeUnit unit) {
        ValueOperations<String, String> ops = template.opsForValue();
        ops.set(key, value, time, unit);
    }

    /**
     * 设置对象存储在redis中
     *
     * @param key
     * @param value
     * @param time
     */

    public void setStr(String key, Object value, Long time) {
        if (value == null) {
            return;
        }
        if (value instanceof String) {
            String obj = (String) value;
            template.opsForValue().set(key, obj);
        } else if (value instanceof List) {
            List obj = (List) value;
            template.opsForList().leftPushAll(key, obj);
        } else if (value instanceof Map) {
            Map obj = (Map) value;
            template.opsForHash().putAll(key, obj);
        }
        if (time != null){
            template.expire(key, time, TimeUnit.SECONDS);
        }

    }

    public String getValue(String key) {
        ValueOperations<String, String> ops = template.opsForValue();
        return ops.get(key);
    }

    public Object getKey(String key) {
        return template.opsForValue().get(key);
    }

    public void delKey(String key) {
        template.delete(key);
    }

    public Long sadd(String key, String value) {
        SetOperations<String, String> ops = template.opsForSet();
        return ops.add(key, value);
    }

    public Set<String> smembers(String key) {
        SetOperations<String, String> ops = template.opsForSet();
        return ops.members(key);
    }

    public void srem(String key, String value) {
        template.boundSetOps(key).remove(value);
    }

    /**
     * 根据下标获取数组元素
     * 返回列表里的元素的索引 index 存储在 key 里面。
     * 下标是从0开始索引的，所以 0 是表示第一个元素， 1 表示第二个元素，并以此类推。
     * 负数索引用于指定从列表尾部开始索引的元素。在这种方法下，-1 表示最后一个元素，-2 表示倒数第二个元素，并以此往前推。
     * 当 key 位置的值不是一个列表的时候，会返回一个error。
     *
     * @param key
     * @param index
     */
    public void listGetByIndex(String key, int index) {
        template.opsForList().index(key, index);
    }

    /**
     * 根据key插入list
     * 把 value 插入存于 key 的列表中在基准值 pivot 的前面或后面。
     * 当 key 不存在时，这个list会被看作是空list，任何操作都不会发生。
     * 当 key 存在，但保存的不是一个list的时候，会返回error。
     *
     * @param key
     * @param value
     */
    public void listInsertByKey(String key, String value) {
        template.opsForList().rightPush(key, value);
    }

    /**
     * 根据key插入list
     * 把 value 插入存于 key 的列表中在基准值 pivot 的前面或后面。
     * 当 key 不存在时，这个list会被看作是空list，任何操作都不会发生。
     * 当 key 存在，但保存的不是一个list的时候，会返回error。
     *
     * @param key
     * @param oldValue
     * @param newValue 要插入的值
     * @param isLeft   是否在newValue之前插入，false为newValue之后插入
     */
    public void listInsertByKey(String key, String oldValue, String newValue, boolean isLeft) {
        if (isLeft) {
            template.opsForList().leftPush(key, oldValue, newValue);
        } else {
            template.opsForList().rightPush(key, oldValue, newValue);
        }
    }

    /**
     * 获取list长度
     *
     * @param key
     */
    public int listSize(String key) {
        return Math.toIntExact(template.opsForList().size(key));
    }

    /**
     * 只有当 key 已经存在并且存着一个 list 的时候，在这个 key 下面的 list 的头部插入 value。
     * 与 LPUSH 相反，当 key 不存在的时候不会进行任何操作。
     *
     * @param key
     * @param value
     */
    public void listInsertByLeftOrRight(String key, String value, boolean isLeft) {
        if (isLeft) {
            template.opsForList().leftPushIfPresent(key, value);
        } else {
            template.opsForList().rightPushIfPresent(key, value);
        }
    }

    /**
     * 返回存储在 key 的列表里指定范围内的元素。
     * start 和 end 偏移量都是基于0的下标，即list的第一个元素下标是0（list的表头），第二个元素下标是1，以此类推。
     * 偏移量也可以是负数，表示偏移量是从list尾部开始计数。 例如， -1 表示列表的最后一个元素，-2 是倒数第二个，以此类推。
     *
     * @param key
     */
    public <T> List<T> listGet(String key, Class<T> clazz) {
        List<String> range = template.opsForList().range(key, 0, -1);
        return JsonUtil.listToListObject(range, clazz);
    }

    /**
     * 返回存储在 key 的列表里指定范围内的元素。
     * start 和 end 偏移量都是基于0的下标，即list的第一个元素下标是0（list的表头），第二个元素下标是1，以此类推。
     * 偏移量也可以是负数，表示偏移量是从list尾部开始计数。 例如， -1 表示列表的最后一个元素，-2 是倒数第二个，以此类推。
     *
     * @param key
     * @param startIndex
     * @param endIndex
     */
    public <T> List<T> listGet(String key, int startIndex, int endIndex, Class<T> clazz) {
        List<String> range = template.opsForList().range(key, startIndex, endIndex);
        return JsonUtil.listToListObject(range, clazz);
    }

    /**
     * 删除元素
     *
     * @param key
     * @param value
     */
    public void listDelete(String key, String value) {
        template.opsForList().remove(key, 0, value);
    }

    /**
     * 删除整个list
     *
     * @param key
     */
    public void listDelete(String key) {
        template.opsForList().trim(key, 1, 0);
    }

    /**
     * 更新元素
     *
     * @param key
     * @param index
     * @param value
     */
    public void listUpdate(String key, int index, String value) {
        template.opsForList().set(key, index, value);
    }
}
